package com.nanfang51g3.ckz.di;

import android.app.Application;
import android.content.Context;

import com.facebook.stetho.okhttp3.StethoInterceptor;
import com.franmontiel.persistentcookiejar.ClearableCookieJar;
import com.franmontiel.persistentcookiejar.PersistentCookieJar;
import com.franmontiel.persistentcookiejar.cache.SetCookieCache;
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor;
import com.nanfang51g3.ckz.R;
import com.nanfang51g3.ckz.http.RestApi;
import com.nanfang51g3.ckz.ui.accounting.AccountingContract;
import com.nanfang51g3.ckz.utils.KLog;
import com.nanfang51g3.ckz.utils.NetWorkUtil;

import java.io.IOException;
import java.io.InputStream;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.inject.Singleton;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import dagger.Module;
import dagger.Provides;
import okhttp3.CertificatePinner;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import okio.Buffer;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Headers;
import retrofit2.http.Path;

/**
 * Created by Administrator on 2016/4/12.
 */
@Module
public class ApiModule {

    Context mContext;

    public ApiModule(Context context) {
        KLog.i("TAG", context == null ? "进入了...ApiModule-is null" : "进入了...ApiModule-not null");
        this.mContext = context;
    }

    @Provides
    @Singleton
    protected RestApi provideRestApi(Retrofit retrofit) {
        KLog.i("TAG", retrofit == null ? "进入了...provideRestApi-is null" : "进入了...provideRestApi-not null");
        return retrofit.create(RestApi.class);
    }

    private static final String F_BREAK = " %n";
    private static final String F_URL = " %s";
    private static final String F_TIME = " in %.1fms";
    private static final String F_HEADERS = "%s";
    private static final String F_RESPONSE = F_BREAK + "Response: %d";
    private static final String F_BODY = "body: %s";

    private static final String F_BREAKER = F_BREAK + "-------------------------------------------" + F_BREAK;
    private static final String F_REQUEST_WITHOUT_BODY = F_URL + F_TIME + F_BREAK + F_HEADERS;
    private static final String F_RESPONSE_WITHOUT_BODY = F_RESPONSE + F_BREAK + F_HEADERS + F_BREAKER;
    private static final String F_REQUEST_WITH_BODY = F_URL + F_TIME + F_BREAK + F_HEADERS + F_BODY + F_BREAK;
    private static final String F_RESPONSE_WITH_BODY = F_RESPONSE + F_BREAK + F_HEADERS + F_BODY + F_BREAK + F_BREAKER;

    @Provides
    @Singleton
    protected Retrofit provideRetrofit() {
        KLog.i("TAG", "进入了...provideRetrofit");
        //添加StethoInterceptor调试
        OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
        builder.addNetworkInterceptor(new StethoInterceptor());
        //日志拦截器
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
        builder.addInterceptor(logging);
        //请求头拦截器 http://blog.yzapp.cn/Retrofit1.html  http://stackoverflow.com/questions/28696964/okhttp-how-to-log-request-body
        builder.addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                KLog.e("retrofit-->", "-进入拦截器...-");
                Request.Builder requestBuilder = request.newBuilder();
                Request signedRequest = requestBuilder
                        .addHeader("Source", "1")
//                        .addHeader("Channel", AppUtil.getChanel(context))
//                        .addHeader("IMEI", AppUtil.getImeiCode(context))
//                        .addHeader("UserId", QicheChaorenApplication.getInstance().getUserId() + "")
//                        .addHeader("Version", AppUtil.getAppVersionName(context))
//                        .addHeader("Net", "" + NetWorkUtil.getNetWorkType(context))
//                        .addHeader("Token", TOKEN)
//                        .addHeader("SessionId", "" + QicheChaorenApplication.getInstance().getSessionId())
                        .build();
                long t1 = System.nanoTime();
                Response response = chain.proceed(signedRequest);
                long t2 = System.nanoTime();
                MediaType contentType = null;
                String bodyString = null;
                if (response.body() != null) {
                    contentType = response.body().contentType();
                    bodyString = response.body().string();
                }
                // 请求响应时间
                double time = (t2 - t1) / 1e6d;
                switch (request.method()) {
                    case "GET":
                        KLog.e("retrofit-->",
                                String.format("GET " + F_REQUEST_WITHOUT_BODY + F_RESPONSE_WITH_BODY,
                                        signedRequest.url(),
                                        time,
                                        signedRequest.headers(),
                                        response.code(),
                                        response.headers(),
                                        stringifyResponseBody(bodyString)));
                        break;
                    case "POST":
                        KLog.e("retrofit-->",
                                String.format("POST " + F_REQUEST_WITH_BODY + F_RESPONSE_WITH_BODY,
                                        signedRequest.url(),
                                        time,
                                        signedRequest.headers(),
                                        stringifyRequestBody(signedRequest),
                                        response.code(),
                                        response.headers(),
                                        stringifyResponseBody(bodyString)));
                        break;
                    case "PUT":
                        KLog.e("retrofit-->",
                                String.format("PUT " + F_REQUEST_WITH_BODY + F_RESPONSE_WITH_BODY,
                                        signedRequest.url(),
                                        time,
                                        signedRequest.headers(),
                                        signedRequest.body().toString(),
                                        response.code(),
                                        response.headers(),
                                        stringifyResponseBody(bodyString)));
                        break;
                    case "DELETE":
                        KLog.e("retrofit-->",
                                String.format("DELETE " + F_REQUEST_WITHOUT_BODY + F_RESPONSE_WITHOUT_BODY,
                                        signedRequest.url(),
                                        time,
                                        signedRequest.headers(),
                                        response.code(),
                                        response.headers()));
                        break;
                }
                if (response.body() != null) {
                    // 深坑！
                    // 打印body后原ResponseBody会被清空，需要重新设置body
                    ResponseBody body = ResponseBody.create(contentType, bodyString);
                    return response.newBuilder().body(body).build();
                } else {
                    return response;
                }
            }
        });


        //持久化cookie
//        ClearableCookieJar cookieJar =
//                new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(null));
//        builder.cookieJar(cookieJar);


        //单个请求头
//        @Headers({
//                "Accept: application/vnd.github.v3.full+json",
//                "User-Agent: Retrofit-your-App"})‘
//        @get("users/{username}")
//        Call<User> getUser(@Path("username") String username);
        //添加证书 http://blog.csdn.net/sk719887916/article/details/51597816
//        builder.certificatePinner(new CertificatePinner.Builder()
//                .add("YOU API.com", "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=")
//                .add("YOU API..com", "sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=")
//                .add("YOU API..com", "sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=")
//                .add("YOU API..com", "sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=")
//                .build());


//          https
//        http://ju.outofmemory.cn/entry/272040


       /* try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            InputStream caInput = context.getResources().openRawResource(R.raw.ca);
            Certificate ca = null;
            ca = certificateFactory.generateCertificate(caInput);
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            if (ca == null) {
                return null;
            }
            keyStore.setCertificateEntry("ca", ca);
            String algorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm);
            trustManagerFactory.init(keyStore);
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
            sslSocketFactory = sslContext.getSocketFactory();
        } catch (Exception e) {

        }

        builder.sslSocketFactory(sslSocketFactory);*/

        try {
//            SSLSocketFactory sslSocketFactory = getSSLSocketFactory_Certificate(mContext, "BKS", R.raw.srca);
            SSLSocketFactory sslSocketFactory = getSSLSocketFactory_Certificate(mContext, "BKS", R.raw.test_server);
            builder.sslSocketFactory(sslSocketFactory);
//            设置setNameVerifie
//            String hosts[] = {"https//:aaaa,com", "https//:bbb.com"};
//            builder.hostnameVerifier(getHostnameVerifier(hosts));
        } catch (Exception e) {
            e.printStackTrace();
        }
        builder.retryOnConnectionFailure(true);//设置出现错误重新连接
        builder.connectTimeout(15, TimeUnit.SECONDS);//设置超时时间
        OkHttpClient okHttpClient = builder.build();


        return new Retrofit.Builder()
                .client(okHttpClient)

                .addConverterFactory(GsonConverterFactory.create()) // 添加GSon转换器
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 添加Rx适配器
                .baseUrl(RestApi.BASE_URL)
                .build();
    }

    protected   HostnameVerifier getHostnameVerifier(final String[] hostUrls) {

        HostnameVerifier TRUSTED_VERIFIER = new HostnameVerifier() {

            public boolean verify(String hostname, SSLSession session) {
                boolean ret = false;
                for (String host : hostUrls) {
                    if (host.equalsIgnoreCase(hostname)) {
                        ret = true;
                    }
                }
                return ret;
            }
        };

        return TRUSTED_VERIFIER;
    }

    X509TrustManager x509TrustManager = null;

    private SSLSocketFactory getSSLSocketFactory_Certificate(Context context, String keyStoreType, int keystoreResId)

            throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException {

        CertificateFactory cf = CertificateFactory.getInstance("X.509");

        InputStream caInput = context.getResources().openRawResource(keystoreResId);
        Certificate ca;
        try {
            ca = cf.generateCertificate(caInput);
            System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
        } finally {
            caInput.close();
        }
        // Create a KeyStore containing our trusted CAs
        if (keyStoreType == null || keyStoreType.length() == 0) {

            keyStoreType = KeyStore.getDefaultType();

        }

        KeyStore keyStore = KeyStore.getInstance(keyStoreType);

        keyStore.load(null, null);

        keyStore.setCertificateEntry("ca", ca);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);

        tmf.init(keyStore);

        TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());


// Create an SSLContext that uses our TrustManager
        SSLContext sslContext = SSLContext.getInstance("TLS");

        sslContext.init(null, wrappedTrustManagers, null);

        return sslContext.getSocketFactory();

    }

    X509TrustManager originalTrustManager;

    private TrustManager[] getWrappedTrustManagers(TrustManager[] trustManagers) {

        originalTrustManager = (X509TrustManager) trustManagers[0];

        return new TrustManager[]{

                new X509TrustManager() {

                    public X509Certificate[] getAcceptedIssuers() {

                        return originalTrustManager.getAcceptedIssuers();

                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) {

                        try {

                            originalTrustManager.checkClientTrusted(certs, authType);

                        } catch (CertificateException e) {

                            e.printStackTrace();

                        }

                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) {

                        try {

                            originalTrustManager.checkServerTrusted(certs, authType);

                        } catch (CertificateException e) {

                            e.printStackTrace();

                        }

                    }

                }

        };
    }

    private static String stringifyRequestBody(Request request) {
        try {
            final Request copy = request.newBuilder().build();
            final Buffer buffer = new Buffer();
            copy.body().writeTo(buffer);
            return buffer.readUtf8();
        } catch (final IOException e) {
            return "did not work";
        }
    }

    public String stringifyResponseBody(String responseBody) {
        return responseBody;
    }

}
